package com.systop.asset.service.impl;

import com.systop.asset.entity.Inventory;
import com.systop.asset.entity.MaterialDisposal;
import com.systop.asset.entity.MaterialDisposalDetail;
import com.systop.asset.exception.SystemException;
import com.systop.asset.mapper.InventoryMapper;
import com.systop.asset.mapper.MaterialDisposalMapper;
import com.systop.asset.service.IMaterialDisposalService;
import com.systop.asset.utils.RandomCodeGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Random;

/**
 * <p>ClassName : MaterialDisposalServiceImpl</p>
 * <p>Description : 物资处置服务实现类</p>
 *
 * @author 孙伟光
 * @version 1.0
 * @date 2025/7/7 15:51
 */
@Service
public class MaterialDisposalServiceImpl implements IMaterialDisposalService {

    @Autowired
    private MaterialDisposalMapper materialDisposalMapper;

    @Autowired
    private InventoryMapper  inventoryMapper;

    /**
     * 根据ID查询物资处置信息（仅主表信息）
     * <p>通过物资处置记录ID查询对应的物资处置主表信息，若记录不存在则抛出异常</p>
     *
     * @param id 物资处置记录ID，不能为null
     * @return MaterialDisposal 物资处置实体对象，包含主表信息
     * @throws SystemException 当查询结果为空时抛出404异常，提示"物资处置记录不存在"
     * @see SystemException 系统异常类
     * @see MaterialDisposalMapper#selectMaterialDisposalById(Long) 底层Mapper接口方法
     */
    @Override
    public MaterialDisposal selectMaterialDisposalById(Long id) {
        // 校验ID是否为空
        if (id == null) {
            throw new SystemException(400, "物资处置记录ID不能为空");
        }
        // 调用Mapper层方法查询物资处置主表信息
        MaterialDisposal materialDisposal = materialDisposalMapper.selectMaterialDisposalById(id);
        // 校验查询结果，若为空则抛出异常
        if (materialDisposal == null) {
            throw new SystemException(404, "物资处置记录不存在");
        }
        // 返回查询到的物资处置实体对象
        return materialDisposal;
    }

    /**
     * 根据ID查询物资处置详细信息（包含主表和明细表信息）
     * <p>通过物资处置记录ID查询对应的物资处置信息，包含主表信息和关联的明细信息，
     * 若记录不存在则抛出异常</p>
     *
     * @param id 物资处置记录ID，不能为null
     * @return MaterialDisposal 物资处置实体对象，包含主表和明细信息
     * @throws SystemException 当查询结果为空时抛出404异常，提示"物资处置记录不存在"
     * @see SystemException 系统异常类
     * @see MaterialDisposalMapper#selectMaterialDisposalMetailById(Long) 底层Mapper接口方法
     */
    @Override
    public MaterialDisposal getMaterialDisposalDetailById(Long id) {
        // 校验ID是否为空
        if (id == null) {
            throw new SystemException(400, "物资处置记录ID不能为空");
        }
        // 调用Mapper层方法查询物资处置信息（包含主表和明细）
        MaterialDisposal materialDisposal = materialDisposalMapper.selectMaterialDisposalMetailById(id);
        // 校验查询结果，若为空则抛出异常
        if (materialDisposal == null) {
            throw new SystemException(404, "物资处置记录不存在");
        }
        // 返回查询到的物资处置实体对象（包含明细信息）
        return materialDisposal;
    }

    /**
     * 查询物资处置记录列表
     * <p>根据查询条件获取物资处置记录列表，支持条件筛选</p>
     *
     * @param materialDisposal 物资处置查询条件对象，可为null表示查询所有记录
     * @return List<MaterialDisposal> 物资处置记录列表，若无记录返回空列表
     * @see MaterialDisposalMapper#selectMateriaDisposalList(MaterialDisposal) 底层Mapper接口方法
     */
    @Override
    public List<MaterialDisposal> selectMaterialDisposalList(MaterialDisposal materialDisposal) {
        return materialDisposalMapper.selectMateriaDisposalList(materialDisposal);
    }

    /**
     * 新增物资处置记录（包含主表和明细表）
     * <p>1. 验证参数有效性 2. 自动生成处置单号 3. 设置默认值 4. 保存主表和明细数据</p>
     *
     * @param materialDisposal 物资处置信息对象，不能为null
     * @return 影响的行数
     * @throws SystemException 当参数无效或保存失败时抛出异常
     */
    @Override
    @Transactional
    public int insertMaterialDisposal(MaterialDisposal materialDisposal) {
        // 1. 参数验证
        if (materialDisposal == null) {
            throw new SystemException(400, "物资处置信息不能为空");
        }
        if (materialDisposal.getMaterialDisposalDetails() == null ||
            materialDisposal.getMaterialDisposalDetails().isEmpty()) {
            throw new SystemException(400, "物资处置明细不能为空");
        }

        // 2. 自动生成处置单号
        String disposalNo = RandomCodeGenerator.generateDisposalCode();
        materialDisposal.setOrderNo(disposalNo);

        // 3. 设置默认值 管理员添加的处置单默认就是已处置
        materialDisposal.setStatus(1);
        materialDisposal.setOperatorId((Long) SecurityContextHolder.getContext().getAuthentication().getCredentials());
        materialDisposal.setOperator((String) SecurityContextHolder.getContext().getAuthentication().getPrincipal());

        // 4. 插入主表
        int rows = materialDisposalMapper.insertMaterialDisposal(materialDisposal);
        if (rows <= 0) {
            throw new SystemException(500, "物资处置主表保存失败");
        }

        // 5. 插入明细表
        materialDisposal.getMaterialDisposalDetails().forEach(detail -> {
            // 明细数据校验
            if (detail.getMaterialId() == null || detail.getQuantity() == null) {
                throw new SystemException(400, "物资明细信息不完整");
            }
            if (detail.getQuantity() <= 0) {
                throw new SystemException(400, "物资数量必须大于0");
            }
            if (detail.getQuantity() > detail.getStock()) {
                throw new SystemException(400, "物资数量不能超过库存量");
            }

            // 设置关联ID和默认值
            detail.setDisposalId(materialDisposal.getId());

            int detailRows = materialDisposalMapper.insertMaterialDisposalDetail(detail);
            if (detailRows <= 0) {
                throw new SystemException(500, "物资处置明细保存失败");
            }

            //更新库存
            // 创建库存查询条件对象
            Inventory inventory = new Inventory();
            inventory.setMaterialId(detail.getMaterialId());
            inventory.setWarehouseId(materialDisposal.getWarehouseId());

            // 查询库存数据
            List<Inventory> rows1 = inventoryMapper.selectInventoryList(inventory);

            // 如果查询到库存记录，则更新库存数量
            if (rows1 != null && !rows1.isEmpty()) {
                // 获取第一条库存记录并减少相应数量
                rows1.get(0).setQuantity(rows1.get(0).getQuantity() - detail.getQuantity());
                // 更新库存记录
                int rows2 = inventoryMapper.updateInventory(rows1.get(0));
                if (rows2 <= 0) {
                    throw new SystemException(500, "库存更新失败");
                }
            }
        });

        return rows;
    }

    /**
     * 更新物资处置记录（包含主表和明细表）
     * <p>1. 验证参数有效性 2. 检查处置状态 3. 更新主表信息 4. 更新明细数据</p>
     *
     * @param materialDisposal 物资处置信息对象，不能为null
     * @return 影响的行数
     * @throws SystemException 当参数无效或更新失败时抛出异常
     */
    @Override
    @Transactional
    public int updateMaterialDisposal(MaterialDisposal materialDisposal) {
        // 1. 参数验证
        if (materialDisposal == null || materialDisposal.getId() == null) {
            throw new SystemException(400, "物资处置信息不能为空");
        }
        if (materialDisposal.getMaterialDisposalDetails() == null ||
            materialDisposal.getMaterialDisposalDetails().isEmpty()) {
            throw new SystemException(400, "物资处置明细不能为空");
        }

        // 2. 检查原记录状态（只有待审核状态可修改）
        MaterialDisposal existing = materialDisposalMapper.selectMaterialDisposalMetailById(materialDisposal.getId());
        if (existing == null) {
            throw new SystemException(404, "物资处置记录不存在");
        }
        if (existing.getStatus() != 1) { // 1-待审核
            throw new SystemException(400, "只有待审核状态的处置单可以修改");
        }

        // 3. 设置更新信息
        materialDisposal.setOperatorId((Long) SecurityContextHolder.getContext().getAuthentication().getCredentials());
        materialDisposal.setOperator((String) SecurityContextHolder.getContext().getAuthentication().getPrincipal());

        // 4. 更新主表
        int rows = materialDisposalMapper.updateMaterialDisposal(materialDisposal);
        if (rows <= 0) {
            throw new SystemException(500, "物资处置主表更新失败");
        }

        //根据处置单找到对应的详情然后归退库存数据

        // 5. 更新明细表（先删除后插入）
        materialDisposalMapper.deleteMaterialDisposalDetailByDisposalId(materialDisposal.getId());

        materialDisposal.getMaterialDisposalDetails().forEach(detail -> {
            // 明细数据校验
            if (detail.getMaterialId() == null || detail.getQuantity() == null) {
                throw new SystemException(400, "物资明细信息不完整");
            }
            if (detail.getQuantity() <= 0) {
                throw new SystemException(400, "物资数量必须大于0");
            }
            if (detail.getQuantity() > detail.getStock()) {
                throw new SystemException(400, "物资数量不能超过库存量");
            }

            // 设置关联ID
            detail.setDisposalId(materialDisposal.getId());

            int detailRows = materialDisposalMapper.insertMaterialDisposalDetail(detail);

            //根据对应的详情然后归更新库存数据

            if (detailRows <= 0) {
                throw new SystemException(500, "物资处置明细更新失败");
            }
        });

        return rows;
    }

    /**
     * 删除单个物资处置记录（包含主表和明细表）
     * <p>1. 验证参数有效性 2. 检查处置状态 3. 删除明细表 4. 删除主表</p>
     *
     * @param id 物资处置记录ID，不能为null
     * @return 影响的行数
     * @throws SystemException 当参数无效或删除失败时抛出异常
     */
    @Override
    @Transactional
    public int deleteMaterialDisposalById(Long id) {
        // 1. 参数验证
        if (id == null) {
            throw new SystemException(400, "物资处置记录ID不能为空");
        }

        // 2. 检查原记录状态（只有待审核状态可删除）
        MaterialDisposal existing = materialDisposalMapper.selectMaterialDisposalMetailById(id);
        if (existing == null) {
            throw new SystemException(404, "物资处置记录不存在");
        }
        if (existing.getStatus() != 1) { // 1-待审核
            throw new SystemException(400, "只有待审核状态的处置单可以删除");
        }

        //还原库存
        List<MaterialDisposalDetail> disposalDetails = existing.getMaterialDisposalDetails();
        for (MaterialDisposalDetail materialDisposalDetail : disposalDetails) {
            Inventory inventory = new Inventory();
            inventory.setMaterialId(materialDisposalDetail.getMaterialId());
            inventory.setWarehouseId(existing.getWarehouseId());
            List<Inventory> inventoryList = inventoryMapper.selectInventoryList(inventory);
            if (inventoryList != null && !inventoryList.isEmpty()) {
                inventoryList.get(0).setQuantity(inventoryList.get(0).getQuantity() + materialDisposalDetail.getQuantity());
                inventoryMapper.updateInventory(inventoryList.get(0));
            }
        }

        // 3. 先删除明细表
        int detailRows = materialDisposalMapper.deleteMaterialDisposalDetailByDisposalId(id);
        if (detailRows < 0) {
            throw new SystemException(500, "物资处置明细删除失败");
        }

        // 4. 再删除主表
        int rows = materialDisposalMapper.deleteMaterialDisposalById(id);
        if (rows <= 0) {
            throw new SystemException(500, "物资处置主表删除失败");
        }

        return rows;
    }

    /**
     * 批量删除物资处置记录（包含主表和明细表）
     * <p>1. 验证参数有效性 2. 检查处置状态 3. 批量删除明细表 4. 批量删除主表</p>
     *
     * @param ids 物资处置记录ID数组，不能为null或空
     * @return 影响的行数
     * @throws SystemException 当参数无效或删除失败时抛出异常
     */
    @Override
    @Transactional
    public int deleteMaterialDisposalByIds(Long[] ids) {
        // 1. 参数验证
        if (ids == null || ids.length == 0) {
            throw new SystemException(400, "物资处置记录ID列表不能为空");
        }

        // 2. 检查所有记录状态（只有待审核状态可删除）
        for (Long id : ids) {
            MaterialDisposal existing = materialDisposalMapper.selectMaterialDisposalMetailById(id);
            if (existing == null) {
                throw new SystemException(404, "物资处置记录(ID:" + id + ")不存在");
            }
            if (existing.getStatus() != 1) { // 1-待审核
                throw new SystemException(400, "物资处置记录(ID:" + id + ")不是待审核状态，不能删除");
            }

            //还原库存
            List<MaterialDisposalDetail> disposalDetails = existing.getMaterialDisposalDetails();
            for (MaterialDisposalDetail materialDisposalDetail : disposalDetails) {
                Inventory inventory = new Inventory();
                inventory.setMaterialId(materialDisposalDetail.getMaterialId());
                inventory.setWarehouseId(existing.getWarehouseId());
                List<Inventory> inventoryList = inventoryMapper.selectInventoryList(inventory);
                if (inventoryList != null && !inventoryList.isEmpty()) {
                    inventoryList.get(0).setQuantity(inventoryList.get(0).getQuantity() + materialDisposalDetail.getQuantity());
                    inventoryMapper.updateInventory(inventoryList.get(0));
                }
            }
        }

        // 3. 先批量删除明细表
        int detailRows = materialDisposalMapper.deleteMaterialDisposalDetailByDisposalIds(ids);
        if (detailRows < 0) {
            throw new SystemException(500, "物资处置明细批量删除失败");
        }

        // 4. 再批量删除主表
        int rows = materialDisposalMapper.deleteMaterialDisposalByIds(ids);
        if (rows <= 0) {
            throw new SystemException(500, "物资处置主表批量删除失败");
        }

        return rows;
    }
}
